package cn.dansj.common.utils.spring.request;

import cn.dansj.common.utils.http.URLUtils;
import cn.dansj.common.utils.transfer.ArrayUtils;
import cn.dansj.common.utils.transfer.Verification;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public abstract class RestTemplateUtils {
    private static final Logger logger = LoggerFactory.getLogger(RestTemplateUtils.class);

    // 默认客户端实例
    private static final RestClient DEFAULT_CLIENT = new Builder().build();

    // 私有构造函数防止实例化
    private RestTemplateUtils() {
    }

    // 静态方法区域 ======================================================
    public static <T> T get(String url, Class<T> responseType) {
        return DEFAULT_CLIENT.get(url, responseType);
    }

    public static <T> T get(String url, ParameterizedTypeReference<T> responseType) {
        return DEFAULT_CLIENT.get(url, responseType);
    }

    public static <T> T get(String url, Map<String, Object> data, ParameterizedTypeReference<T> responseType, HttpHeaders headers) {
        return DEFAULT_CLIENT.get(url, data, responseType, headers);
    }

    public static <T> T get(String url, Map<String, Object> data, Class<T> responseType) {
        return DEFAULT_CLIENT.get(url, data, responseType);
    }

    public static <T> T get(String url, Map<String, Object> data, Class<T> responseType, HttpHeaders headers) {
        return DEFAULT_CLIENT.get(url, data, responseType, headers);
    }

    public static <T> T get(String url, Map<String, Object> data, ParameterizedTypeReference<T> responseType) {
        return DEFAULT_CLIENT.get(url, data, responseType);
    }

    public static <T> T get(String url, Class<T> responseType, HttpHeaders headers, Object... uriVariables) {
        return DEFAULT_CLIENT.get(url, responseType, headers, uriVariables);
    }

    public static <T> T get(String url, ParameterizedTypeReference<T> responseType, HttpHeaders headers, Object... uriVariables) {
        return DEFAULT_CLIENT.get(url, responseType, headers, uriVariables);
    }

    public static <T> T post(String url, Class<T> responseType) {
        return DEFAULT_CLIENT.post(url, responseType);
    }

    public static <T> T post(String url, ParameterizedTypeReference<T> responseType) {
        return DEFAULT_CLIENT.post(url, responseType);
    }

    public static <T> T post(String url, Map<String, Object> data, Class<T> responseType) {
        return DEFAULT_CLIENT.post(url, data, responseType);
    }

    public static <T> T post(String url, Map<String, Object> data, ParameterizedTypeReference<T> responseType) {
        return DEFAULT_CLIENT.post(url, data, responseType);
    }

    public static <T> T post(String url, Map<String, Object> data, Class<T> responseType, HttpHeaders headers) {
        return DEFAULT_CLIENT.post(url, data, responseType, headers);
    }

    public static <T> T post(String url, Map<String, Object> data, ParameterizedTypeReference<T> responseType, HttpHeaders headers) {
        return DEFAULT_CLIENT.post(url, data, responseType, headers);
    }

    public static <T> T delete(String url, Class<T> responseType, HttpHeaders headers) {
        return DEFAULT_CLIENT.delete(url, responseType, headers);
    }

    public static <T> T put(String url, Class<T> responseType, HttpHeaders headers, Object body) {
        return DEFAULT_CLIENT.put(url, responseType, headers, body);
    }
    // 结束静态方法区域 ======================================================

    public static RestTemplate getRestTemplate() {
        return DEFAULT_CLIENT.getRestTemplate();
    }

    public static Builder builder() {
        return new Builder();
    }

    // 客户端类封装所有请求方法
    public static class RestClient {
        private final RestTemplate restTemplate;
        private final HttpHeaders defaultHeaders;

        private RestClient(ClientHttpRequestFactoryUtils.HttpClientPoolConfig httpClientPoolConfig, HttpHeaders httpHeaders) {
            restTemplate = new RestTemplate(ClientHttpRequestFactoryUtils.create(httpClientPoolConfig));
            restTemplate.getMessageConverters().add(JacksonHttpMessageConverter.JACKSON_HTTP_MESSAGE_CONVERTER);
            restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
            defaultHeaders = httpHeaders;
        }

        public RestTemplate getRestTemplate() {
            return restTemplate;
        }

        private HttpEntity<?> getHttpEntity() {
            return new HttpEntity<>(defaultHeaders);
        }

        private HttpEntity<?> getHttpEntity(HttpHeaders headers) {
            return new HttpEntity<>(mergeHeaders(defaultHeaders, headers));
        }

        private static HttpHeaders mergeHeaders(HttpHeaders headers, HttpHeaders newHeaders) {
            if (newHeaders == null) return headers;
            HttpHeaders httpHeaders = new HttpHeaders();
            headers.forEach((key, value) -> {
                List<String> nonNullList = ArrayUtils.removeIf(value, Verification::checkNull);
                if (nonNullList != null && !nonNullList.isEmpty()) httpHeaders.put(key, nonNullList);
            });
            newHeaders.forEach((key, value) -> {
                List<String> nonNullList = ArrayUtils.removeIf(value, Verification::checkNull);
                if (nonNullList != null && !nonNullList.isEmpty()) httpHeaders.put(key, nonNullList);
            });
            return httpHeaders;
        }

        private HttpEntity<?> getHttpEntity(Object data, HttpHeaders headers) {
            return new HttpEntity<>(data, mergeHeaders(defaultHeaders, headers));
        }

        private HttpEntity<?> getHttpEntity(Object data) {
            return new HttpEntity<>(data, defaultHeaders);
        }

        public <T> T get(String url, Map<String, Object> data, Class<T> responseType) {
            return restTemplate.exchange(url + URLUtils.joinParams(data), HttpMethod.GET, getHttpEntity(), responseType).getBody();
        }

        public <T> T get(String url, Map<String, Object> data, ParameterizedTypeReference<T> responseType) {
            return restTemplate.exchange(url + URLUtils.joinParams(data), HttpMethod.GET, getHttpEntity(), responseType).getBody();
        }

        public <T> T get(String url, Map<String, Object> data, ParameterizedTypeReference<T> responseType, HttpHeaders headers) {
            return restTemplate.exchange(url + URLUtils.joinParams(data), HttpMethod.GET, getHttpEntity(headers), responseType).getBody();
        }

        public <T> T get(String url, Map<String, Object> data, Class<T> responseType, HttpHeaders headers) {
            return restTemplate.exchange(url + URLUtils.joinParams(data), HttpMethod.GET, getHttpEntity(headers), responseType).getBody();
        }

        public <T> T get(String url, Class<T> responseType) {
            return restTemplate.exchange(url, HttpMethod.GET, getHttpEntity(), responseType).getBody();
        }

        public <T> T get(String url, ParameterizedTypeReference<T> responseType) {
            return restTemplate.exchange(url, HttpMethod.GET, getHttpEntity(), responseType).getBody();
        }

        public <T> T get(String url, Class<T> responseType, HttpHeaders headers, Object... uriVariables) {
            return restTemplate.exchange(url, HttpMethod.GET, getHttpEntity(headers), responseType, uriVariables).getBody();
        }

        public <T> T get(String url, ParameterizedTypeReference<T> responseType, HttpHeaders headers, Object... uriVariables) {
            return restTemplate.exchange(url, HttpMethod.GET, getHttpEntity(headers), responseType, uriVariables).getBody();
        }

        public <T> T post(String url, Class<T> responseType) {
            return restTemplate.exchange(url, HttpMethod.POST, getHttpEntity(), responseType).getBody();
        }

        public <T> T post(String url, ParameterizedTypeReference<T> responseType) {
            return restTemplate.exchange(url, HttpMethod.POST, getHttpEntity(), responseType).getBody();
        }

        public <T> T post(String url, Map<String, Object> data, Class<T> responseType) {
            return restTemplate.exchange(url, HttpMethod.POST, getHttpEntity(data), responseType).getBody();
        }

        public <T> T post(String url, Map<String, Object> data, ParameterizedTypeReference<T> responseType) {
            return restTemplate.exchange(url, HttpMethod.POST, getHttpEntity(data), responseType).getBody();
        }

        public <T> T post(String url, Map<String, Object> data, Class<T> responseType, HttpHeaders headers) {
            return restTemplate.exchange(url, HttpMethod.POST, getHttpEntity(data, headers), responseType).getBody();
        }

        public <T> T post(String url, Map<String, Object> data, ParameterizedTypeReference<T> responseType, HttpHeaders headers) {
            return restTemplate.exchange(url, HttpMethod.POST, getHttpEntity(data, headers), responseType).getBody();
        }

        public <T> T delete(String url, Class<T> responseType, HttpHeaders headers) {
            return restTemplate.exchange(url, HttpMethod.DELETE, getHttpEntity(headers), responseType).getBody();
        }

        public <T> T put(String url, Class<T> responseType, HttpHeaders headers, Object body) {
            return restTemplate.exchange(url, HttpMethod.PUT, getHttpEntity(body, headers), responseType).getBody();
        }
    }

    // Builder 类
    public static class Builder {
        private int connectionRequestTimeout = 1000;
        // 连接超时
        private int connectionTimeout = 10000;
        // 同路由并发数 # 每个路由的最大连接数,如果只调用一个地址,可以将其设置为最大连接数
        private int maxPerRoute = 100;
        // 池最大数 连接池的最大连接数，0代表不限
        private int maxTotal = 200;
        // 数据读取超时时间
        private int socketTimeout = 10000;
        private int retryTimes = 1;
        private int retryInterval = 10;
        // 生产环境默认严格验证
        private boolean strictHostnameVerification = true;
        // 生产环境默认不信任所有证书
        private boolean trustAllCertificates = false;
        private HttpHeaders httpHeaders = new HttpHeaders();

        private Builder() {
        }

        // 缓存容器：键为配置的唯一标识，值为实例
        private static final ConcurrentHashMap<String, RestClient> INSTANCE_CACHE = new ConcurrentHashMap<>();

        public Builder connectionRequestTimeout(int connectionRequestTimeout) {
            this.connectionRequestTimeout = connectionRequestTimeout;
            return this;
        }

        public Builder connectionTimeout(int connectionTimeout) {
            this.connectionTimeout = connectionTimeout;
            return this;
        }

        public Builder maxPerRoute(int maxPerRoute) {
            this.maxPerRoute = maxPerRoute;
            return this;
        }

        public Builder maxTotal(int maxTotal) {
            this.maxTotal = maxTotal;
            return this;
        }

        public Builder socketTimeout(int socketTimeout) {
            this.socketTimeout = socketTimeout;
            return this;
        }

        public Builder retryTimes(int retryTimes) {
            this.retryTimes = retryTimes;
            return this;
        }

        public Builder retryInterval(int retryInterval) {
            this.retryInterval = retryInterval;
            return this;
        }

        public Builder strictHostnameVerification(boolean strictHostnameVerification) {
            this.strictHostnameVerification = strictHostnameVerification;
            return this;
        }

        public Builder trustAllCertificates(boolean trustAllCertificates) {
            this.trustAllCertificates = trustAllCertificates;
            return this;
        }

        public Builder httpHeaders(HttpHeaders httpHeaders) {
            this.httpHeaders = httpHeaders;
            return this;
        }

        public Builder basicAuth(String username, String password) {
            this.httpHeaders.setBasicAuth(username, password);
            return this;
        }

        public RestClient build() {
            String key = generateKey();
            return INSTANCE_CACHE.computeIfAbsent(key, k -> {
                ClientHttpRequestFactoryUtils.HttpClientPoolConfig config = new ClientHttpRequestFactoryUtils.HttpClientPoolConfig();
                logger.info("HttpClientPoolConfig ==>\n{}", config);
                config.setMaxTotal(maxTotal);
                config.setMaxPerRoute(maxPerRoute);
                config.setRetryTimes(retryTimes);
                config.setRetryInterval(retryInterval);
                config.setStrictHostnameVerification(strictHostnameVerification);
                config.setSocketTimeout(socketTimeout);
                config.setConnectionRequestTimeout(connectionRequestTimeout);
                config.setConnectionTimeout(connectionTimeout);
                config.setTrustAllCertificates(trustAllCertificates);
                return new RestClient(config, httpHeaders);
            });
        }

        private String generateKey() {
            return maxTotal + "_" + maxPerRoute + "_" + retryTimes + "_" + retryInterval + "_" + strictHostnameVerification + "_" + trustAllCertificates + "_"
                    + socketTimeout + "_" + connectionRequestTimeout + "_" + connectionRequestTimeout + "_" + connectionTimeout + "_" + trustAllCertificates + "_" + httpHeaders.hashCode();
        }
    }
}